﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Script.Serialization;
using Sausage.Common;
using Sausage.Web.Code;
using Sausage.Web.DataModel;
using Sausage.Web.Models;
using Telerik.Web.Mvc;

namespace Sausage.Web.Domain
{
    public class MaintainPlanHelper
    {
        public static GridModel<object> Select(JosnPagingQueryModel query)
        {
            Guid targetID;
            var isWithChild = Helper.IsNeedOrganizationQuery(query, out targetID);
            List<Guid> organization = OrganizationHelper.GetAllowedOrganizationList(isWithChild, targetID);
            using (var context = new SausageEntities())
            {
                return
                    QueryMaintainPlan(
                        context.MaintainPlan.Where(
                            item =>
                            organization.Contains(item.OrganizationID) &&
                            (item.State == (int)MaintainDataStateEnum.Confirmed)),
                        query, isWithChild);
            }
        }

        public static GridModel<object> SubmitSelect(JosnPagingQueryModel query)
        {
            Guid targetID;
            var isWithChild = Helper.IsNeedOrganizationQuery(query, out targetID);
            List<Guid> organization = OrganizationHelper.GetAllowedOrganizationList(isWithChild, targetID);
            using (var context = new SausageEntities())
            {
                return
                    QueryMaintainPlan(
                        context.MaintainPlan.Where(
                            item =>
                            organization.Contains(item.OrganizationID) &&
                            (item.State == (int)MaintainDataStateEnum.Unsubmit ||
                             item.State == (int)MaintainDataStateEnum.AuditRejected)),
                        query, isWithChild);
            }
        }

        public static GridModel<object> AuditSelect(JosnPagingQueryModel query)
        {
            Guid targetID;
            var isWithChild = Helper.IsNeedOrganizationQuery(query, out targetID);
            List<Guid> organization = OrganizationHelper.GetAllowedOrganizationList(isWithChild, targetID);
            using (var context = new SausageEntities())
            {
                return
                    QueryMaintainPlan(context.MaintainPlan.Where(item =>
                    organization.Contains(item.OrganizationID) &&
                    (item.State == (int)MaintainDataStateEnum.Submitted ||
                     item.State == (int)MaintainDataStateEnum.ConfirmationRejected))
                    , query, isWithChild);
            }
        }

        public static GridModel<object> ConfirmSelect(JosnPagingQueryModel query)
        {
            Guid targetID;
            var isWithChild = Helper.IsNeedOrganizationQuery(query, out targetID);
            List<Guid> organization = OrganizationHelper.GetAllowedOrganizationList(isWithChild, targetID);
            using (var context = new SausageEntities())
            {
                return
                    QueryMaintainPlan(context.MaintainPlan.Where(item =>
                    organization.Contains(item.OrganizationID) && item.State == (int)MaintainDataStateEnum.Audited)
                    , query, isWithChild);
            }
        }


        private static GridModel<object> QueryMaintainPlan(IQueryable<MaintainPlan> source, JosnPagingQueryModel query, bool isWithChild)
        {
            var result = UIHelper.GetGridModelFromQueryModel<MaintainPlan>(
                source,
                query.page,
                query.limit,
                GetSortDescriptorFromQueryModel(query.SortModel),
                GetSearchFilterFromQueryModel(query.FilterModel, isWithChild));

            var list = result.Data.Select(item => new
            {
                item.PlanID,
                item.OrganizationID,
                Organization = item.Organization.OrganizationName,
                item.CreateDate,
                item.Applicant,
                item.ApplicationDate,
                item.Amount,
                item.Auditor,
                item.AuditedDate,
                item.Approver,
                item.ApprovedDate,
                item.State,
                item.IsDelay,
                item.Memo,
                item.Comment
            }).ToList();

            return new GridModel<object>()
            {
                Aggregates = result.Aggregates,
                Data = list,
                Total = result.Total
            };
        }

        private static List<IFilterDescriptor> GetSearchFilterFromQueryModel(IEnumerable<JosnQueryFilterModel> filterModels, bool isWithChild)
        {
            var filterList = new List<IFilterDescriptor>();
            foreach (var item in filterModels)
            {
                if (string.IsNullOrEmpty(item.value))
                    continue;

                if (item.property == "OrganizationID" && isWithChild)
                    continue; 
                
                if (item.property.EndsWith("ID", StringComparison.InvariantCultureIgnoreCase))
                {
                    var targetID = Guid.Parse(item.value);
                    if (targetID != Guid.Empty)
                        filterList.Add(new FilterDescriptor(item.property, FilterOperator.IsEqualTo, targetID));
                }
                else if (item.property == "ApplicationDate_L") //startData - begin
                {
                    var targetDate = DateTime.Parse(item.value);
                    filterList.Add(new FilterDescriptor("ApplicationDate", FilterOperator.IsGreaterThanOrEqualTo, targetDate));
                }
                else if (item.property == "ApplicationDate_H") // startDate - end.
                {
                    var targetDate = DateTime.Parse(item.value);
                    filterList.Add(new FilterDescriptor("ApplicationDate", FilterOperator.IsLessThanOrEqualTo, targetDate));
                }
                else //other filter.
                    filterList.Add(new FilterDescriptor(item.property, FilterOperator.Contains, item.value));
            }
            return filterList;
        }

        private static List<SortDescriptor> GetSortDescriptorFromQueryModel(IEnumerable<JosnQuerySortModel> sortModels)
        {
            //convert the sort description.
            var sortList = new List<SortDescriptor>();
            foreach (var item in sortModels)
            {
                var descriptor = new SortDescriptor()
                {
                    Member = item.property,
                    SortDirection =
                        item.direction.ToLower() == "desc"
                            ? ListSortDirection.Descending
                            : ListSortDirection.Ascending
                };

                if (descriptor.Member == "Organization")
                    descriptor.Member = "Organization.OrganizationName";

                sortList.Add(descriptor);
            }
            return sortList;
        }

        public static MaintainPlanListRow GetMaintainPlanByID(Guid id)
        {
            using (var context = new SausageEntities())
            {
                var data =
                    context.MaintainPlan.Include("Organization").Include("Items").Include("Items.MaintainCategory").
                        FirstOrDefault(item => item.PlanID == id);

                if (data == null)
                    return null;

                var result = new MaintainPlanListRow();
                result.PlanID = data.PlanID;
                result.OrganizationID = data.OrganizationID;
                result.Organization = data.Organization.OrganizationName;
                result.CreateDate = data.CreateDate;
                result.Applicant = data.Applicant;
                result.ApplicationDate = data.ApplicationDate;
                result.Amount = data.Amount;
                result.Auditor = data.Auditor;
                result.AuditedDate = data.AuditedDate;
                result.Approver = data.Approver;
                result.ApprovedDate = data.ApprovedDate;
                result.State = data.State;
                result.IsDelay = data.IsDelay;
                result.Memo = data.Memo;

                var list = new List<MaintainPlanItemListRow>();
                foreach (var item in data.Items)
                {
                    list.Add(new MaintainPlanItemListRow()
                                 {
                                     PlanID = data.PlanID,
                                     PlanItemID = item.PlanItemID,
                                     CategoryID = item.CategoryID,
                                     Category = item.MaintainCategory.CategoryName,
                                     Quantity = item.Quantity,
                                     Price = item.Price,
                                     Amount = item.Amount,
                                     Unit = item.MaintainCategory.Unit
                                 });
                }

                result.Items = list.ToArray();
                return result;
            }
        }

        public static void DeleteMaintainPlan(Guid planID)
        {
            using (var context = new SausageEntities())
            {
                //Delete the Maintain Plan Item
                var list = context.MaintainPlanItem.Where(item => item.PlanID == planID).ToList();
                foreach (var item in list)
                    context.DeleteObject(item);

                //Delete the Maintain Plan
                var maintainPlan = new MaintainPlan { PlanID = planID };
                context.CreateObjectSet<MaintainPlan>().Attach(maintainPlan);
                context.DeleteObject(maintainPlan);
                context.SaveChanges();
            }
        }

        public static void CreateMaintainPlan(MaintainPlanListRow data)
        {
            using (var context = new SausageEntities())
            {
                var maintainPlan = new MaintainPlan();
                maintainPlan.PlanID = Guid.NewGuid();
                maintainPlan.OrganizationID = Helper.CurrentPrincipal.User.OrganizationID;
                maintainPlan.CreateDate = DateTime.Now;
                maintainPlan.Amount = data.Items.Sum(item => item.Quantity * item.Price);
                maintainPlan.Applicant = Helper.CurrentPrincipal.User.UserName;
                maintainPlan.ApplicationDate = data.ApplicationDate;
                maintainPlan.State = (int)MaintainDataStateEnum.Unsubmit;
                maintainPlan.Memo = data.Memo;
                maintainPlan.IsDelay = Helper.IsPlanDelay(data.ApplicationDate);
                context.AddToMaintainPlan(maintainPlan);

                foreach (var item in data.Items)
                {
                    var maintainPlanItem = new MaintainPlanItem();
                    maintainPlanItem.PlanID = maintainPlan.PlanID;
                    maintainPlanItem.PlanItemID = Guid.NewGuid();
                    maintainPlanItem.CategoryID = item.CategoryID;
                    maintainPlanItem.Quantity = item.Quantity;
                    maintainPlanItem.Price = item.Price;
                    maintainPlanItem.Amount = item.Quantity * item.Price;
                    context.AddToMaintainPlanItem(maintainPlanItem);
                }

                context.SaveChanges();
            }
        }

        public static bool CouldCreateMaintainPlan(DateTime time, out string errorMessage)
        {
            //一周一个单位，只能有一个养护计划，不管状态是否为提交。
            DateTime beginDateTime, endDateTime;
            time.GetWeekRange(out beginDateTime, out endDateTime);

            using (var context = new SausageEntities())
            {
                var hasPlan = context.MaintainPlan.Any(item => (item.ApplicationDate >= beginDateTime) &&
                                                               (item.ApplicationDate <= endDateTime) &&
                                                               item.OrganizationID == Helper.CurrentPrincipal.User.OrganizationID);
                if (hasPlan)
                {
                    errorMessage = "此周养护计划已经填写,不能再次填写,如果养护计划未申报,请修改未申报的养护计划!";
                    return false;
                }

            }

            errorMessage = string.Empty;
            return true;
        }

        public static bool CouldUpdateMaintainPlan(DateTime time, Guid planID, out string errorMessage)
        {
            //一周一个单位，只能有一个养护计划，不管状态是否为提交。
            DateTime beginDateTime, endDateTime;
            time.GetWeekRange(out beginDateTime, out endDateTime);

            using (var context = new SausageEntities())
            {
                var hasPlan = context.MaintainPlan.Any(item => (item.ApplicationDate >= beginDateTime) &&
                                                               (item.ApplicationDate <= endDateTime) &&
                                                               item.OrganizationID ==
                                                               Helper.CurrentPrincipal.User.OrganizationID
                                                               && item.PlanID != planID);
                if (hasPlan)
                {
                    errorMessage = "此周养护计划已经填写,不能再次填写,如果养护计划未申报,请修改未申报的养护计划!";
                    return false;
                }

            }

            errorMessage = string.Empty;
            return true;
        }

        public static void UpdateMaintainPlan(MaintainPlanListRow data)
        {
            using (var context = new SausageEntities())
            {
                var target = context.MaintainPlan.FirstOrDefault(item => item.PlanID == data.PlanID);
                if (target == null)
                    return;

                if (target.State != (int)MaintainDataStateEnum.Unsubmit && target.State != (int)MaintainDataStateEnum.AuditRejected)
                    throw new SausageException(string.Format("养护计划已经提交，不允许执行编辑操作。"));

                target.Applicant = Helper.CurrentPrincipal.User.UserName;
                target.ApplicationDate = data.ApplicationDate;
                target.Amount = data.Items.Sum(item => item.Quantity * item.Price);
                target.Memo = data.Memo;

                //delete all the item.
                var list = context.MaintainPlanItem.Where(item => item.PlanID == data.PlanID).ToList();
                foreach (var item in list)
                {
                    context.CreateObjectSet<MaintainPlanItem>().Attach(item);
                    context.ObjectStateManager.ChangeObjectState(item, EntityState.Deleted);
                }

                //insert the new item.
                foreach (var item in data.Items)
                {
                    var maintainPlanItem = new MaintainPlanItem();
                    maintainPlanItem.PlanID = data.PlanID;
                    maintainPlanItem.PlanItemID = Guid.NewGuid();
                    maintainPlanItem.CategoryID = item.CategoryID;
                    maintainPlanItem.Quantity = item.Quantity;
                    maintainPlanItem.Price = item.Price;
                    maintainPlanItem.Amount = item.Quantity * item.Price;
                    context.AddToMaintainPlanItem(maintainPlanItem);
                }

                context.SaveChanges();
            }
        }


        public static void UpdateMaintainPlanState(Guid id, int state)
        {
            using (var context = new SausageEntities())
            {
                var maintainPlan = context.MaintainPlan.FirstOrDefault(item => item.PlanID == id);
                if (maintainPlan == null)
                    return;

                maintainPlan.State = state;
                context.SaveChanges();
            }
        }

        public static void ExecuteSubmit(Guid[] plans)
        {
            if (null != plans && plans.Length > 0)
            {
                using (var context = new SausageEntities())
                {
                    var list = context.MaintainPlan.Where(item => plans.Contains(item.PlanID)).ToList();

                    foreach (var maintainPlan in list)
                    {
                        maintainPlan.State = (int)MaintainDataStateEnum.Submitted;
                    }
                    context.SaveChanges();
                }
            }
        }

        public static void ExecuteAudit(Guid[] plans, bool passed, string comment)
        {
            if (null != plans && plans.Length > 0)
            {
                using (var context = new SausageEntities())
                {
                    var list = context.MaintainPlan.Where(item => plans.Contains(item.PlanID)).ToList();

                    foreach (var maintainPlan in list)
                    {
                        maintainPlan.Auditor = Helper.CurrentPrincipal.User.UserName;
                        maintainPlan.AuditedDate = DateTime.Now;
                        maintainPlan.Comment = comment;
                        maintainPlan.State = passed
                                                     ? (int)MaintainDataStateEnum.Audited
                                                     : (int)MaintainDataStateEnum.AuditRejected;
                    }
                    context.SaveChanges();
                }
            }
        }

        public static void ExecuteConfirm(Guid[] plans, bool passed, string comment)
        {
            if (null != plans && plans.Length > 0)
            {
                using (var context = new SausageEntities())
                {
                    var list = context.MaintainPlan.Where(item => plans.Contains(item.PlanID)).ToList();

                    foreach (var maintainPlan in list)
                    {
                        maintainPlan.Auditor = Helper.CurrentPrincipal.User.UserName;
                        maintainPlan.AuditedDate = DateTime.Now;
                        maintainPlan.Comment = comment;
                        maintainPlan.State = passed
                                                     ? (int)MaintainDataStateEnum.Confirmed
                                                     : (int)MaintainDataStateEnum.ConfirmationRejected;
                    }
                    context.SaveChanges();
                }
            }
        }
    }
}
